﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using __ts.Core.Service;
using __ts.Core.Service.IdleChecher;
using log4net;
using __ts.Core.Api;

/*
 *  author: able
 *  @2012/2/21 17:20:36
 * 
 */
namespace __ts.Core.Transport.Tcp.Nio
{
    /// <summary>
    /// 
    /// </summary>
    public class NioTcpServer : AbstractTcpServer
    {
        static ILog LOG = LogManager.GetLogger(typeof(NioTcpServer));

        // the idle checker is used for detecting read or write idle session 
        private IdleChecker idleChecker = new IndexedIdleChecker();

        // list of bound addresses
        private HashSet<SocketAddress> addresses = new HashSet<SocketAddress>();

        // the strategy for dispatching servers and client to selector threads.
        private SelectorStrategy strategy;

        private SocketSessionConfig config;

        private bool reuseAddress = false;

        public NioTcpServer(SelectorStrategy strategy)
        {
            this.strategy = strategy;
            this.config = new DefaultSocketSessionConfig();
        }

        public override IoSessionConfig getSessionConfig()
        {
            return config;
        }

        public void setSessionConfig(SocketSessionConfig config)
        {
            this.config = config;
        }

        public override void setReuseAddress(bool reuseAddress)
        {
            this.reuseAddress = reuseAddress;
        }

        public override bool isReuseAddress()
        {
            return reuseAddress;
        }

        public override void bind(params SocketAddress[] localAddress)
        {
            if (localAddress == null)
            {
                // We should at least have one address to bind on
                throw new Exception("LocalAdress cannot be null");
            }

            foreach (SocketAddress address in localAddress)
            {
                // check if the address is already bound
                //synchronized (this) {
                if (addresses.Contains(address))
                {
                    throw new IOException("address " + address + " already bound");
                }

                //LOG.Debug("binding address {}", address);

                addresses.Add(address);
                NioSelectorProcessor processor = (NioSelectorProcessor)strategy.getSelectorForBindNewAddress();
                processor.bindAndAcceptAddress(this, address);
                if (addresses.Count == 1)
                {
                    // it's the first address bound, let's fire the event
                    fireServiceActivated();
                }
                //}
            }
        }

        public override HashSet<SocketAddress> getLocalAddresses()
        {
            return addresses;
        }

        public override void unbind(params SocketAddress[] localAddresses)
        {
            foreach (SocketAddress socketAddress in localAddresses)
            {
                //LOG.Debug("unbinding {}", socketAddress);
                //synchronized (this) {
                strategy.unbind(socketAddress);
                addresses.Remove(socketAddress);
                if (addresses.Count < 1)
                {
                    fireServiceInactivated();
                }
                //}
            }
        }

        public override void unbindAll()
        {
            foreach (SocketAddress socketAddress in addresses)
            {
                unbind(socketAddress);
            }
        }
    }
}